package com.rfsp.mcp.service.interfaceclient;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.rfsp.common.base.BaseService;
import com.rfsp.common.base.ResultVO;
import com.rfsp.common.util.*;
import com.rfsp.mcp.enums.TransCodeEnum;
import com.rfsp.mcp.feign.McpRelayFeign;
import com.rfsp.mcp.mapper.*;
import com.rfsp.mcp.pojo.dto.FlowDTO;
import com.rfsp.mcp.pojo.dto.MiPayInfoDto;
import com.rfsp.mcp.pojo.po.FlowPO;
import com.rfsp.mcp.pojo.po.MiPayPO;
import com.rfsp.mcp.pojo.po.PfmPO;
import com.rfsp.mcp.pojo.vo.*;
import com.rfsp.mcp.service.FlowService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.util.*;

@Service
public class WSMiPayService extends BaseService<MiPayPO> {
    public Logger logger = LoggerFactory.getLogger(WSMiPayService.class);
    @Autowired
    private MiPayMapper miPayMapper;
    @Autowired
    private FlowMapper flowMapper;
    @Autowired
    private PfmMapper pfmMapper;
    @Autowired
    private WsItfMapper wsItfMapper;

    @Autowired
    McpRelayFeign feign;
    @Autowired
    FlowService flowService;

    @Value("${mcp.file-path-paylog}")
    private String filePath;

    @Autowired
    private MCPWsKeyMapper mCPWsKeyMapper;

    @Transactional
    public ResultVO<String> queryMiPayInfo(MiPayInfoDto miPayInfoDto){
            //-----业务执行-----
            FlowDTO response_flow=new FlowDTO();
        try{
            //1、通过医保平台ID，获取医保平台信息
            String pfmOrgCode = "";
            String edType = "";//加密类型：0表示不加密，1表示SM2加密
            String orgpub = "";//ORG_PUB对接系统加密公钥
            String plfpri = "";//PLF_PRI平台解密私钥
            String transCode = TransCodeEnum.M1003.getKey();//接口代码 "M1003";
            String msgId = UUID.randomUUID().toString();//流水号

            String sendDate = DateUtil.dateFormatStr("yyyyMMdd");//接口请求日期
            String sendTime = DateUtil.dateFormatStr("HHmmss");//接口请求时间
            if(miPayInfoDto==null){
                return ResultVO.fail("orgDirectoryDto参数不能为空");
            }else if(miPayInfoDto.getPfmId()==null){
                return ResultVO.fail("PfmId不能为空");
            }else {
                PfmPO pfmPO = pfmMapper.selectByPrimaryKey(miPayInfoDto.getPfmId());
                if(pfmPO!=null){
                    pfmOrgCode = pfmPO.getPfmOrgCode();//医保系统的统一社会信用代码
                    edType = pfmPO.getEdType();//加密类型：0表示不加密，1表示SM2加密
                }else{
                    return ResultVO.fail("PfmId参数值错误，请检查");
                }
            }
            if(miPayInfoDto.getMiOrgCode()==null){
                return ResultVO.fail("miOrgCode不能为空");
            }

            String payStartDate = miPayInfoDto.getPayStartDate();//申请查询结算起始日期
            if(payStartDate!=null&&DateUtil.isValidDate(payStartDate,"yyyy-MM-dd")==false){
                return ResultVO.fail("payStartDate参数格式不正确");
            }
            String payEndDate = miPayInfoDto.getPayEndDate();//申请查询结算终止日期
            if(payEndDate!=null&&DateUtil.isValidDate(payEndDate,"yyyy-MM-dd")==false){
                return ResultVO.fail("payEndDate参数格式不正确");
            }

            //判断请求是否需要加密解密
            if(!StringUtils.isEmpty(edType)&&"1".equals(edType)){//如需要加密
                //如果需要加密,则获取对应的 公私钥
                Map<String, Object> wsKeyPara = new HashMap<String, Object>();
                wsKeyPara.put("fk_org_id", miPayInfoDto.getPfmId());//医保局平台id
                List<Map<String, Object>> wsKeylist = mCPWsKeyMapper.getWsKey(wsKeyPara);
                if(null != wsKeylist && !wsKeylist.isEmpty()) {
                    Map<String, Object> map = wsKeylist.get(0);
                    orgpub = map.get("orgpub")==null?"":map.get("orgpub").toString();//ORG_PUB对接系统加密公钥
                    plfpri = map.get("plfpri")==null?"":map.get("plfpri").toString();//PLF_PRI平台解密私钥
                    if(StringUtils.isEmpty(orgpub)||StringUtils.isEmpty(plfpri)){
                        return ResultVO.fail("如需要SM2加密，对接系统加密公钥和平台解密私钥不能为空值，请检查");
                    }
                }else{
                    return ResultVO.fail("未查到该平台SM2加密信息，请检查");
                }
            }

            //组装json请求报文
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode json = objectMapper.createObjectNode();
            json.put("pfmOrgCode", pfmOrgCode);
            json.put("transCode", transCode);
            json.put("msgId", msgId);
            json.put("sendDate", sendDate);
            json.put("sendTime", sendTime);
            json.put("fixmedinsCode", miPayInfoDto.getMiOrgCode());
            json.put("begndate", payStartDate);
            json.put("enddate", payEndDate);
            json.put("mark1", "");
            json.put("mark2", "");
            json.put("mark3", "");
            // 转换为字符串
            String jsonString = json.toString();

            //2、获取接口配置管理中医保局平台URL和转发应用URL
            String forWordUrl = "";//转发程序URL
            URI baseUri = null;
            String pfmUrl = "";//医保局平台系统url
            String status = "";//接口状态
            Map<String, Object> para = new HashMap<String, Object>();
            para.put("org_id", miPayInfoDto.getPfmId());//医保平台id
            para.put("code", TransCodeEnum.M1003.getKey());//接口代码M1003
            List<Map<String, Object>> list = wsItfMapper.getBizIdByItf(para);
            if(null != list && !list.isEmpty()){
                Map<String, Object> map = list.get(0);
                pfmUrl = map.get("uri")==null?"":map.get("uri").toString();//医保局平台URL
                if(StringUtils.isEmpty(pfmUrl)){
                    return ResultVO.fail("接口配置信息表中，医保局平台URL值为空");
                }
                forWordUrl = map.get("url")==null?"":map.get("url").toString();//转发系统URL
                if(StringUtils.isEmpty(forWordUrl)){
                    return ResultVO.fail("接口配置信息表中，转发系统URL值为空");
                }
                status = map.get("status")==null?"":map.get("status").toString();//接口状态
                if(StringUtils.isEmpty(status)){
                    return ResultVO.fail("接口配置信息表中，接口状态值为空");
                }else if(!"1".equals(status)){
                    return ResultVO.fail("接口配置信息表中，接口状态值为停用");
                }
                baseUri = new URI(forWordUrl);
            }else{
                return ResultVO.fail("没有接口配置信息");
            }

            //3、先生成一条请求流水数据信息和将请求报文json文件落地
            FlowDTO request_flow=new FlowDTO();
            request_flow.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
            request_flow.setCurrentNo(msgId);//请求流水号
            request_flow.setTransCode(TransCodeEnum.M1003.getKey());
            request_flow.setStatus("4");//处理成功
            request_flow.setInFlag("1");//请求方向 1：请求
            request_flow.setOrgNo(pfmOrgCode);//医保局平台组织机构代码
            request_flow.setOperation("0");//接口业务方向：0平台到医保系统
            request_flow.setPfmId(miPayInfoDto.getPfmId());
            request_flow.setLogId(miPayInfoDto.getLogId());//查询记录信息Log

            //以接口请求方向代码+请求流水号（唯一值）作为文件名
            String request_fileName=request_flow.getInFlag()+request_flow.getCurrentNo()+".txt";
            String request_filePath = this.filePath.replaceFirst("date/", StringUtil.dateToString(new Date(), "yyyy/MM/dd/"));
            request_flow.setContEncript(request_filePath+request_fileName);//文件路径+名称
            request_flow.setSdate(new Date());
            request_flow.setStime(new Date());
            request_flow.setEdate(new Date());
            request_flow.setEtime(new Date());
            //存储落地json文件
            FileUtil.create(request_filePath,request_fileName,jsonString,false);
            //保存接口流水表
            createFlow(request_flow);


            //4、调用转发服务进行查询，返回json报文
            List<OrgYbjMiPayVO> lData = new ArrayList<>();
            //判断请求是否需要sm2加密解密
            McpInterfaceResultVO resultVO = null;
            if(!StringUtils.isEmpty(edType)&&"1".equals(edType)){
                resultVO = feign.queryMiPayInfo(baseUri,pfmUrl,jsonString,edType,orgpub,plfpri);
            }else{
                resultVO = feign.queryMiPayInfo(baseUri,pfmUrl,jsonString,edType,"","");
            }

            //5、插入响应信息接口流水和报文文件落地（成功或失败都需要插流水和落文件）
            response_flow.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
            response_flow.setCurrentNo(msgId);//请求流水号
            response_flow.setTransCode(TransCodeEnum.M1003.getKey());
            response_flow.setStatus("4");//处理成功
            response_flow.setInFlag("2");//请求方向 2:响应
            response_flow.setOrgNo(pfmOrgCode);//医保局平台组织机构代码
            response_flow.setOperation("1");//接口业务方向：1：医保系统到平台
            response_flow.setPfmId(miPayInfoDto.getPfmId());
            response_flow.setLogId(miPayInfoDto.getLogId());//查询记录信息Log

            ObjectMapper mapper = new ObjectMapper();
            String content="";
            try {
                content += mapper.writeValueAsString(resultVO);
            } catch (JsonProcessingException e) {
                logger.error(e.getMessage());
                e.printStackTrace();
            }
            content+="\n\n";
            //以接口响应方向+请求流水号（唯一值）作为文件名
            String response_fileName=response_flow.getInFlag()+response_flow.getCurrentNo()+".txt";
            String response_filePath = this.filePath.replaceFirst("date/", StringUtil.dateToString(new Date(), "yyyy/MM/dd/"));
            response_flow.setContEncript(response_filePath+response_fileName);//文件路径+名称
            response_flow.setSdate(new Date());
            response_flow.setStime(new Date());
            response_flow.setEdate(new Date());
            response_flow.setEtime(new Date());
            //存储落地json文件
            FileUtil.create(response_filePath,response_fileName,content,false);
            //保存接口流水表
            createFlow(response_flow);

            //6、----保存结算信息数据-----
            if(resultVO!=null&&resultVO.getMsg().equals("success")){
                //存储医保局定点机构信息表名录信息
                String jsonResult = resultVO.getData();
                //判断返回的JSON是否包含数据
                if(!StringUtils.isEmpty(jsonResult)&&!JsonUtil.isEmptyJson(jsonResult)) {
                    lData = JsonUtil.toBeanList(jsonResult, OrgYbjMiPayVO.class, "payInfoList");
                    //boolean isStorageStatus = true;//存储状态，当有一条失败时，就将流水表状态设置为失败，且在json文件中标出错误信息
                    StringBuffer errBuffer = new StringBuffer();//如存在存储失败的记录，记录失败原因，写入到json文件中，且置流水表状态为失败
                    if (lData != null && lData.size() > 0) {
                        for (OrgYbjMiPayVO vo : lData) {
                            vo.setPayLogId(miPayInfoDto.getLogId());//插入查询记录log_id
                            vo.setTargetOrgId(miPayInfoDto.getMiOrgId());//被查询机构ID
                            vo.setPfmId(miPayInfoDto.getPfmId());//医保平台ID
                            saveMiPayInfo(vo, miPayInfoDto, errBuffer);
                        }
                    }
                    //判断是否有存储失败的记录
                    if (errBuffer.length() > 0) {
                        //1、变更流水表状态为失败
                        FlowPO queryPo = new FlowPO();
                        queryPo.setAid(response_flow.getAid());
                        queryPo.setPfmId(response_flow.getPfmId());
                        queryPo.setLogId(response_flow.getLogId());
                        List<FlowPO> listFlowPo = flowService.queryList(queryPo);
                        if (listFlowPo != null && listFlowPo.size() > 0) {
                            FlowPO po = listFlowPo.get(0);
                            po.setStatus("3");//处理失败
                            flowService.update(po);
                        }
                        //2、重写json文件，增加存储失败信息
                        ObjectMapper objectMapperAdd = new ObjectMapper();
                        File jsonFile = new File(response_flow.getContEncript());
                        try {
                            // 读取JSON文件到Map对象（或其他Java对象）
                            Map<String, Object> jsonMap = objectMapperAdd.readValue(jsonFile, Map.class);
                            // 修改Java对象（这里是Map）
                            jsonMap.put("isStoragefailed", "failed");
                            jsonMap.put("storagefailedMsg", errBuffer.toString());
                            // 将修改后的对象写回JSON文件
                            objectMapper.writeValue(jsonFile, jsonMap); // 或者使用Files工具类覆盖原文件内容，例如：Files.write(Paths.get("path/to/your/data.json"), objectMapper.writeValueAsBytes(jsonMap));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        //如果所有记录全存储失败，没有一条成功存储的，直接返回上层应用 处理失败
                        if (lData.size() == StringUtil.countSubstring(errBuffer.toString(), "||")) {
                            return ResultVO.fail("同步医保资金月度结算信息失败");
                        }
                    }
                }
                //-----执行成功-----
                return ResultVO.success("queryOrgSubjectInfo请求处理成功");

            }else{
                //向上层应用返回调用失败
                logger.error("=====转发应用调用医保局平台接口服务失败=====");
                return ResultVO.fail("转发应用调用医保局平台接口服务失败");
            }
        }catch (Exception e){
            //1、变更流水表状态为失败
            if(!StringUtils.isEmpty(response_flow.getAid())) {
                FlowPO queryPo = new FlowPO();
                queryPo.setAid(response_flow.getAid());
                queryPo.setPfmId(response_flow.getPfmId());
                queryPo.setLogId(response_flow.getLogId());
                List<FlowPO> listFlowPo = flowService.queryList(queryPo);
                if (listFlowPo != null && listFlowPo.size() > 0) {
                    FlowPO po = listFlowPo.get(0);
                    po.setStatus("3");//处理失败
                    flowService.update(po);
                }
            }

            logger.error("=========同步医保资金月度结算信息失败:=============,{}",e);
            return ResultVO.fail("同步医保资金月度结算信息失败");
        }
    }

    @Transactional
    public void saveMiPayInfo(OrgYbjMiPayVO vo,MiPayInfoDto miPayInfoDto,StringBuffer errBuffer) throws Exception{
        MiPayPO miPayPO = new MiPayPO();
        try{
            miPayPO = this.makePo(vo,miPayInfoDto);
            this.save(miPayPO);
        }catch (Exception e){
            //可以在这里记录错误日志，但不抛出异常，允许事务继续
            logger.error("=========医保资金月度结算存储信息失败:=============,{}",e);
            //如果某条记录存储失败，则记录在json文件中
            errBuffer.append(e.getMessage()).append("||");
        }

    }

    private Integer createFlow(FlowDTO dto){
        Integer count=flowService.create(dto);
        return count;
    }
    public String getAID() {
        String str = "1234567890qwertyuiopasdfghjklzxcvbnm";
        Random r = new Random();

        StringBuffer sb = new StringBuffer(16);

        for(int i=0;i<16;i++) {
            int index = r.nextInt(str.length());
            sb.append(str.charAt(index));
        }
        return sb.toString();
    }

    private MiPayPO makePo(OrgYbjMiPayVO vo,MiPayInfoDto miPayInfoDto) throws Exception {
        MiPayPO miPayPO = new MiPayPO();
        try {
            if(StringUtils.isEmpty(vo.getPayIdno())){
                throw new Exception("医疗机构代码值不能为空");
            }else{
                miPayPO.setPayIdno(vo.getPayIdno());//医疗机构代码(必填项)
            }
            if(StringUtils.isEmpty(vo.getPayMc())){
                throw new Exception("医疗机构名称值不能为空");
            }else{
                miPayPO.setPayMc(vo.getPayMc());//医疗机构名称(必填项)
            }

            //结算起始日期 申请医保结算的开始日期 格式：YYYY-MM-DD
            miPayPO.setPayStartDate(StringUtils.isEmpty(vo.getPayStartDate())?null:DateUtils.parseDate(vo.getPayStartDate(),"yyyy-MM-dd"));
            //结算终止日期 申请医保结算的结束日期 格式：YYYY-MM-DD
            miPayPO.setPayEndDate(StringUtils.isEmpty(vo.getPayeEndDate())?null:DateUtils.parseDate(vo.getPayeEndDate(),"yyyy-MM-dd"));
            miPayPO.setAreaCode(vo.getAreaCode());//定点机构归属统筹区 医保统筹区
            miPayPO.setPersonTimes(StringUtils.isEmpty(vo.getPersonTimes())?null:Integer.parseInt(vo.getPersonTimes()));//申报人次 当期使用医保支付的患者人次
            miPayPO.setPayApplyFlowno(vo.getPayApplyFlowno());//医保支付申请流水编号 当期申请医保基金支付的系统数据凭证号

            miPayPO.setApplyAmount(StringUtils.isEmpty(vo.getApplyAmount())?null:new BigDecimal(vo.getApplyAmount()));//申报金额（元） 当期使用申请医保支付金额
            miPayPO.setTotalAmount(StringUtils.isEmpty(vo.getTotalAmount())?null:new BigDecimal(vo.getTotalAmount()));//医疗总费用（元） 当期使用医保支付的患者相关的医疗总费用
            miPayPO.setFundPayment(StringUtils.isEmpty(vo.getFundPayment())?null:new BigDecimal(vo.getFundPayment()));//基金支付合计（元） 当期医保基金实际支付的金额
            miPayPO.setAccountPayment(StringUtils.isEmpty(vo.getAccountPayment())?null:new BigDecimal(vo.getAccountPayment()));//账户支付合计（元） 当期使用医保支付的患者“个人医保账户”实际支付合计数
            miPayPO.setCashPayment(StringUtils.isEmpty(vo.getCashPayment())?null:new BigDecimal(vo.getCashPayment()));//现金支付合计（元） 当期使用医保支付的患者经医保报销后，个人需要承担的自费部分（使用现金/银行卡/移动支付等支付合计数）
            //支付时间 资金的实际拨付时间 格式：YYYY-MM-DD HH:mm:ss
            miPayPO.setPayTime(StringUtils.isEmpty(vo.getPayTime())?null:DateUtils.parseDate(vo.getPayTime(),"yyyy-MM-dd HH:mm:ss"));
            miPayPO.setPayRemark(vo.getPayRemark());//支付款项备注 可备注说明支付款项类型，如城乡门诊类型
            miPayPO.setPaymentNature("1");// 款项性质给个默认1 款项性质：1固定取按月拨付金额

            miPayPO.setRemark1(vo.getRemark1());
            miPayPO.setRemark2(vo.getRemark2());
            miPayPO.setRemark3(vo.getRemark3());
            miPayPO.setRemark4(vo.getRemark4());
            miPayPO.setRemark5(vo.getRemark5());
            miPayPO.setRemark6(vo.getRemark6());
            miPayPO.setRemark7(vo.getRemark7());
            miPayPO.setRemark8(vo.getRemark8());
            miPayPO.setRemark9(vo.getRemark9());
            miPayPO.setRemark10(vo.getRemark10());

            //copy完，再补充其他字段项
            miPayPO.setPfmId(vo.getPfmId());//医保平台ID
            miPayPO.setPayLogId(vo.getPayLogId());//查询记录表ID
            miPayPO.setTargetOrgId(vo.getTargetOrgId());//被查询机构ID
            miPayPO.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
            miPayPO.setOptTime(new Date());//操作时间
            miPayPO.setOptType("1");//操作类型（1.新增 2.修改 3.删除）
            miPayPO.setOptUserId(miPayInfoDto.getOptUserId());//操作用户ID
        }catch (Exception e){
            logger.error("=========makePo响应报文中存在属性值格式转换异常，请检查:=============,{}",e);
            throw new Exception("响应报文中存在属性值格式转换异常，请检查："+e.getMessage());
        }
        //return miPayPO;
        return XssUtils.replaceXss(miPayPO);
    }

}
